/*************************************************************
  Cocus Core - A simple PIC16 core emulator for PIC18
  
  version 2.0 by Santiago H. (santiagohssl@gmail.com)

  UNDER GNU LGPL

  file: vmcore.h
*************************************************************/

#include <p18cxxx.h>

#ifndef CORE2_MASTER
#define CORE2_MASTER

// define as 1 to use the usart
#define PERIPH_USART				1


#define CORE_HOOK_DISCARD_OP		1


#define CORE_VECTOR_RESET			0x0000
#define CORE_VECTOR_INT				0x0005


#define COREDEV_RAMSTART			0x12

// OPCODES with opcode=0x0
#define CORE_OP_ZERO				0x00
#define CORE_OP_MOVWF				0x80
#define CORE_OP_RETFIE				0x9
#define CORE_OP_RETURN				0x8
#define CORE_OP_NOP					0x9F


// OPCODES
#define CORE_OP_GOTO				0x05
#define CORE_OP_CALL				0x04


#define CORE_OP_ADDLW				0x1F
#define CORE_OP_SUBLW				0x1E

#define CORE_OP_UNKNOWN				0x3F

#define CORE_OP_BCF					0x04
#define CORE_OP_BSF					0x05

#define CORE_OP_BTFSC				0x06
#define CORE_OP_BTFSS				0x07

#define CORE_OP_MOVLW				0x0C
#define CORE_OP_RETLW				0x0D

#define CORE_OP_ANDLW				0x39
#define CORE_OP_IORLW				0x38
#define CORE_OP_XORLW				0x3A

#define CORE_OP_SWAPF				0x0E

#define CORE_OP_INCFSZ				0x0F
#define CORE_OP_DECFSZ				0x0B

#define CORE_OP_XORWF				0x06
#define CORE_OP_IORWF				0x04

#define CORE_OP_SUBWF				0x02
#define CORE_OP_ADDWF				0x07

#define CORE_OP_ANDWF				0x05
#define CORE_OP_CLRW_CLRF			0x01

#define CORE_OP_INCF				0x0A
#define CORE_OP_DECF				0x03

#define CORE_OP_COMF				0x09
#define CORE_OP_MOVF				0x08

#define CORE_OP_RLF					0x0D
#define CORE_OP_RRF					0x0C

// sfr access definitions
#define COREDEV_SFR_PCL				0x2
#define COREDEV_SFR_PCLATH			0xA
#define COREDEV_SFR_STATUS			0x3
#define COREDEV_SFR_INDF			0x0
#define COREDEV_SFR_FSR				0x4
#define COREDEV_SFR_INTCON			0xB


// bit access definitions
#define COREDEV_BIT_C 				0x0
#define COREDEV_BIT_DC				0x1
#define COREDEV_BIT_Z				0x2
#define COREDEV_BIT_RP0				0x5
#define COREDEV_BIT_RP1				0x6
#define COREDEV_BIT_IRP				0x7
#define COREDEV_BIT_GIE				0x7


/* PIC16 opcode presented in various kinds for easy handling, all uses 2 bytes (and 2 bits of padding) */
typedef union
{
	struct
	{
		char 	data;
		char 	opcode;
	} opcode;
	
	unsigned int packed16;
	
	struct
	{
		unsigned	f:7;
		unsigned	d:1;
		unsigned	op:6;
		unsigned	padding:2;
	} parse6op7f;
	
	struct
	{
		unsigned	paddingLow:1;  		// work-around for C18 boundaries align
		unsigned	f:7;
		unsigned	op:7;
		unsigned	padding:1;
	} parse7op7f;
	
	struct
	{
		unsigned	paddingLow:1;  		// work-around for C18 boundaries align
		unsigned	f:7;
		unsigned	b:3;
		unsigned	op:4;
		unsigned	padding:1;
	} parse4op7f;
	
	struct
	{
		unsigned char	k;
		unsigned	x:1;
		unsigned	op:5;
		unsigned	padding:2;
	} parse5op8k;
	
	struct
	{
		unsigned char k;
		unsigned op:6;
		unsigned padding:2;
	} parse6op8k;
	
	struct
	{
		unsigned char k0;
		unsigned k1:3;
		unsigned op:3;
		unsigned padding:2;
	} parse3op11k;

} vm_opcode;

typedef struct
{
	char			w;
	int				stack[8];
	unsigned char	current_stack;
} core2_header;

typedef struct 
{
	core2_header	info;
	unsigned char	sram[0x3FA];

} core2_vm_1k;


typedef union
{
	struct
	{
		unsigned b0:1;
		unsigned b1:1;
		unsigned b2:1;
		unsigned b3:1;
		unsigned b4:1;
		unsigned b5:1;
		unsigned b6:1;
		unsigned b7:1;		
	} bits;
	unsigned char ch;
} vm_bytebits;

typedef union
{
	struct
	{
		unsigned n0:4;
		unsigned n1:4;
	}nibbles;
	unsigned char ch;
} vm_bytenibbles;

typedef union
{
	struct
	{
		unsigned char low;
		unsigned char high;
	} bytes;
	unsigned int data;
} vm_intbytes;


/* macros for common used bits access */
#define vm_status_get_c(dev)				vm_readSingleBit(dev, COREDEV_SFR_STATUS, COREDEV_BIT_C)
#define vm_status_get_dc(dev)				vm_readSingleBit(dev, COREDEV_SFR_STATUS, COREDEV_BIT_DC)
#define vm_status_get_z(dev)				vm_readSingleBit(dev, COREDEV_SFR_STATUS, COREDEV_BIT_Z)
#define vm_intcon_get_gie(dev)				vm_readSingleBit(dev, COREDEV_SFR_INTCON, COREDEV_BIT_GIE)

#define vm_status_set_c(dev,d)				vm_writeSingleBit(dev, COREDEV_SFR_STATUS, COREDEV_BIT_C, d)
#define vm_status_set_dc(dev,d)				vm_writeSingleBit(dev, COREDEV_SFR_STATUS, COREDEV_BIT_DC, d)
#define vm_status_set_z(dev,d)				vm_writeSingleBit(dev, COREDEV_SFR_STATUS, COREDEV_BIT_Z, d)
#define vm_intcon_set_gie(dev,d)			vm_writeSingleBit(dev, COREDEV_SFR_INTCON, COREDEV_BIT_GIE, d)




void vm_init(void *dev);
char vm_readRam(void *dev, int pos);
void vm_writeRam(void *dev, int pos, char data);

char vm_readRamExposed(void *dev, int pos);
void vm_writeRamExposed(void *dev, int pos, char data);
void vm_writeRamExposedWithW(void *dev, int pos, char data, char target);


char vm_readSingleBit(void *dev, int pos, int bitn);
void vm_writeSingleBit(void *dev, int pos, int bitn, char data);

char vm_readSingleBitExposed(void *dev, int pos, int bitn);
void vm_writeSingleBitExposed(void *dev, int pos, int bitn, char data);


char vm_getBank(void *dev);
unsigned int vm_bankMemDiff(void *dev);
unsigned int vm_getSFRaddress(void *dev, int pos);

void vm_setZifZero(void *dev, char data);

char vm_getW(void *dev);
void vm_setW(void *dev, char w);

unsigned int vm_getPC(void *dev);
void vm_setPC(void *dev, int pc);
void vm_sumPC(void *dev);
unsigned char vm_getSelectedStack(void *dev);
void vm_setSelectedStack(void *dev, char sel);
unsigned int vm_getStackPC(void *dev);
void vm_setStackPC(void *dev, unsigned int pc);

void vm_raiseInt(void *dev);

void vm_runOp(vm_opcode *opcode, void *dev);

#endif